//
//  ADNavigationControllerStack.m
//  ADKit
//
//  Created by 杜 泽旭 on 2017/12/2.
//  Copyright © 2017年 duzexu. All rights reserved.
//

#import "ADNavigationControllerStack.h"
#import "ADKitHeaders.h"

@interface ADNavigationControllerStack ()

@property (nonatomic, weak) id<ADViewModelServices> services;
@property (nonatomic, weak) UIWindow *window;
@property (nonatomic, strong) NSMutableArray *navigationControllers;

@end

@implementation ADNavigationControllerStack

- (instancetype)initWithServices:(id<ADViewModelServices>)services window:(UIWindow *)window {
    self = [super init];
    if (self) {
        self.services = services;
        self.window = window;
        self.navigationControllers = [[NSMutableArray alloc] init];
        [self _registerNavigationHooks];
    }
    return self;
}

- (void)pushNavigationController:(UINavigationController *)navigationController {
    
    if ([self.navigationControllers containsObject:navigationController]) return;
    
    [self.navigationControllers addObject:navigationController];
}

- (void)bringNavigationController:(UINavigationController *)navigationController {
    if ([self.navigationControllers containsObject:navigationController]) {
        [self.navigationControllers removeObject:navigationController];
    }
    [self.navigationControllers addObject:navigationController];
}

- (UINavigationController *)popNavigationController {
    UINavigationController *navigationController = self.navigationControllers.lastObject;
    if (self.navigationControllers.count == 1) {
        return navigationController;
    }
    [self.navigationControllers removeLastObject];
    return self.navigationControllers.lastObject;
}

- (UINavigationController *)topNavigationController {
    return self.navigationControllers.lastObject;
}

- (void)_registerNavigationHooks {
    @weakify(self)
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(pushViewModel:animated:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         ADViewModel *viewModel = tuple.first;
         if ([viewModel respondsToSelector:@selector(viewControllerClass)]) {
             Class cls = [viewModel viewControllerClass];
             if ([cls respondsToSelector:@selector(controllerWithViewModel:)]) {
                 ADViewController *vc = [cls performSelector:@selector(controllerWithViewModel:) withObject:viewModel];
                 [self.topNavigationController pushViewController:vc animated:[tuple.second boolValue]];
             }
         }
     }];
    
    [[[(NSObject *)self.services
     rac_signalForSelector:@selector(pushContextViewModel:animated:)] deliverOnMainThread]
    subscribeNext:^(RACTuple *tuple) {
        @strongify(self)
        ADViewModel *viewModel = tuple.first;
        if ([viewModel respondsToSelector:@selector(viewControllerClass)]) {
            Class cls = [viewModel viewControllerClass];
            if ([cls respondsToSelector:@selector(controllerWithViewModel:)]) {
                UIViewController *presentingViewController = [self.topNavigationController topViewController];

                UIViewController *vc = [cls performSelector:@selector(controllerWithViewModel:) withObject:viewModel];
                if (![vc isKindOfClass:UINavigationController.class]) {
                    vc = [[ADNavigationController alloc] initWithRootViewController:vc];
                }
                [self pushNavigationController:(UINavigationController *)vc];
                
                vc.view.frame = presentingViewController.view.bounds;
                [presentingViewController addChildViewController:vc];
                [presentingViewController.view addSubview:vc.view];
                AD_VoidBlock completion = tuple.third;
                if ([tuple.second boolValue]) {
                    vc.view.transform = CGAffineTransformMakeTranslation(presentingViewController.view.bounds.size.width, 0);
                    [UIView animateWithDuration:0.3 animations:^{
                        vc.view.transform = CGAffineTransformIdentity;
                    } completion:^(BOOL finished) {
                        if (completion) {
                            completion();
                        }
                    }];
                }else{
                    if (completion) {
                        completion();
                    }
                }
            }
        }
    }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(pushViewController:animated:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UIViewController *vc = tuple.first;
         if (vc) {
             [self.topNavigationController pushViewController:vc animated:[tuple.second boolValue]];
         }
     }];
    
    [[[(NSObject *)self.services
     rac_signalForSelector:@selector(pushContextViewController:animated:)] deliverOnMainThread]
    subscribeNext:^(RACTuple *tuple) {
        @strongify(self)
        UIViewController *vc = tuple.first;
        if (vc) {
            UIViewController *presentingViewController = [self.topNavigationController topViewController];
            if (![vc isKindOfClass:UINavigationController.class]) {
                vc = [[ADNavigationController alloc] initWithRootViewController:vc];
            }
            [self pushNavigationController:(UINavigationController *)vc];
            
            vc.view.frame = presentingViewController.view.bounds;
            [presentingViewController addChildViewController:vc];
            [presentingViewController.view addSubview:vc.view];
            AD_VoidBlock completion = tuple.third;
            if ([tuple.second boolValue]) {
                vc.view.transform = CGAffineTransformMakeTranslation(presentingViewController.view.bounds.size.width, 0);
                [UIView animateWithDuration:0.3 animations:^{
                    vc.view.transform = CGAffineTransformIdentity;
                } completion:^(BOOL finished) {
                    if (completion) {
                        completion();
                    }
                }];
            }else{
                if (completion) {
                    completion();
                }
            }
        }
    }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(popViewModelAnimated:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         [self.topNavigationController popViewControllerAnimated:[tuple.first boolValue]];
     }];
    
    [[[(NSObject *)self.services
     rac_signalForSelector:@selector(popContextViewModelAnimated:)] deliverOnMainThread]
    subscribeNext:^(RACTuple *tuple) {
        @strongify(self)
        UINavigationController *vc = self.topNavigationController;
        [self popNavigationController];
        AD_VoidBlock completion = tuple.second;
        if ([tuple.first boolValue]) {
            [UIView animateWithDuration:0.3 animations:^{
                vc.view.transform = CGAffineTransformMakeTranslation(vc.view.frame.size.width, 0);
            } completion:^(BOOL finished) {
                [vc.view removeFromSuperview];
                [vc removeFromParentViewController];
                if (completion) {
                    completion();
                }
            }];
        }else{
            [vc.view removeFromSuperview];
            [vc removeFromParentViewController];
            if (completion) {
                completion();
            }
        }
    }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(popToRootViewModelAnimated:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         [self.topNavigationController popToRootViewControllerAnimated:[tuple.first boolValue]];
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(presentViewModel:animated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         ADViewModel *viewModel = tuple.first;
         if ([viewModel respondsToSelector:@selector(viewControllerClass)]) {
             Class cls = [viewModel viewControllerClass];
             if ([cls respondsToSelector:@selector(controllerWithViewModel:)]) {
                 viewModel.isPresented = YES;
                 UIViewController *vc = [cls performSelector:@selector(controllerWithViewModel:) withObject:viewModel];

                 UINavigationController *presentingViewController = self.navigationControllers.lastObject;
                 if (![vc isKindOfClass:UINavigationController.class]) {
                     vc = [[ADNavigationController alloc] initWithRootViewController:vc];
                 }
                 [self pushNavigationController:(UINavigationController *)vc];
                 
                 [presentingViewController presentViewController:vc animated:[tuple.second boolValue] completion:tuple.third];
             }
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(presentViewController:animated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UIViewController *vc = tuple.first;
         if (vc) {
             UINavigationController *presentingViewController = self.navigationControllers.lastObject;
             if (![vc isKindOfClass:UINavigationController.class]) {
                 vc = [[ADNavigationController alloc] initWithRootViewController:vc];
             }
             [self pushNavigationController:(UINavigationController *)vc];
             
             [presentingViewController presentViewController:vc animated:[tuple.second boolValue] completion:tuple.third];
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(rootPresentViewModel:animated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         ADViewModel *viewModel = tuple.first;
         if ([viewModel respondsToSelector:@selector(viewControllerClass)]) {
             Class cls = [viewModel viewControllerClass];
             if ([cls respondsToSelector:@selector(controllerWithViewModel:)]) {
                 viewModel.isPresented = YES;
                 UIViewController *vc = [cls performSelector:@selector(controllerWithViewModel:) withObject:viewModel];
                 
                 UINavigationController *presentingViewController = ADKit.rootVC;
                 if (![vc isKindOfClass:UINavigationController.class]) {
                     vc = [[ADNavigationController alloc] initWithRootViewController:vc];
                 }
                 [self pushNavigationController:(UINavigationController *)vc];
                 
                 [presentingViewController presentViewController:vc animated:[tuple.second boolValue] completion:tuple.third];
             }
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(rootPresentViewController:animated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UIViewController *vc = tuple.first;
         if (vc) {
             UINavigationController *presentingViewController = ADKit.rootVC;
             if (![vc isKindOfClass:UINavigationController.class]) {
                 vc = [[ADNavigationController alloc] initWithRootViewController:vc];
             }
             [self pushNavigationController:(UINavigationController *)vc];
             
             [presentingViewController presentViewController:vc animated:[tuple.second boolValue] completion:tuple.third];
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(presentContextViewModel:animated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         ADViewModel *viewModel = tuple.first;
         if ([viewModel respondsToSelector:@selector(viewControllerClass)]) {
             Class cls = [viewModel viewControllerClass];
             if ([cls respondsToSelector:@selector(controllerWithViewModel:)]) {
                 UIViewController *presentingViewController = [self.topNavigationController topViewController];

                 UIViewController *vc = [cls performSelector:@selector(controllerWithViewModel:) withObject:viewModel];
                 if (![vc isKindOfClass:UINavigationController.class]) {
                     vc = [[ADNavigationController alloc] initWithRootViewController:vc];
                 }
                 [self pushNavigationController:(UINavigationController *)vc];
                 
                 vc.view.frame = presentingViewController.view.bounds;
                 [presentingViewController addChildViewController:vc];
                 [presentingViewController.view addSubview:vc.view];
                 AD_VoidBlock completion = tuple.third;
                 if ([tuple.second boolValue]) {
                     vc.view.transform = CGAffineTransformMakeTranslation(0, presentingViewController.view.bounds.size.height);
                     [UIView animateWithDuration:0.3 animations:^{
                         vc.view.transform = CGAffineTransformIdentity;
                     } completion:^(BOOL finished) {
                         if (completion) {
                             completion();
                         }
                     }];
                 }else{
                     if (completion) {
                         completion();
                     }
                 }
             }
         }
     }];
    
    [[[(NSObject *)self.services
       rac_signalForSelector:@selector(presentContextViewController:animated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UIViewController *vc = tuple.first;
         if (vc) {
             UIViewController *presentingViewController = [self.topNavigationController topViewController];
             if (![vc isKindOfClass:UINavigationController.class]) {
                 vc = [[ADNavigationController alloc] initWithRootViewController:vc];
             }
             [self pushNavigationController:(UINavigationController *)vc];
             
             vc.view.frame = presentingViewController.view.bounds;
             [presentingViewController addChildViewController:vc];
             [presentingViewController.view addSubview:vc.view];
             AD_VoidBlock completion = tuple.third;
             if ([tuple.second boolValue]) {
                 vc.view.transform = CGAffineTransformMakeTranslation(0, presentingViewController.view.bounds.size.height);
                 [UIView animateWithDuration:0.3 animations:^{
                     vc.view.transform = CGAffineTransformIdentity;
                 } completion:^(BOOL finished) {
                     if (completion) {
                         completion();
                     }
                 }];
             }else{
                 if (completion) {
                     completion();
                 }
             }
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(dismissViewModelAnimated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UINavigationController *vc = self.topNavigationController;
         [self popNavigationController];
         [vc dismissViewControllerAnimated:[tuple.first boolValue] completion:tuple.second];
     }];
    
    [[[(NSObject *)self.services
       rac_signalForSelector:@selector(dismissContextViewModelAnimated:completion:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UINavigationController *vc = self.topNavigationController;
         [self popNavigationController];
         AD_VoidBlock completion = tuple.second;
         if ([tuple.first boolValue]) {
             [UIView animateWithDuration:0.3 animations:^{
                 vc.view.transform = CGAffineTransformMakeTranslation(0, vc.view.frame.size.height);
             } completion:^(BOOL finished) {
                 [vc.view removeFromSuperview];
                 [vc removeFromParentViewController];
                 if (completion) {
                     completion();
                 }
             }];
         }else{
             [vc.view removeFromSuperview];
             [vc removeFromParentViewController];
             if (completion) {
                 completion();
             }
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(resetRootViewModel:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         ADViewModel *viewModel = tuple.first;
         if ([viewModel respondsToSelector:@selector(viewControllerClass)]) {
             Class cls = [viewModel viewControllerClass];
             if ([cls respondsToSelector:@selector(controllerWithViewModel:)]) {
                 [self.navigationControllers removeAllObjects];
                 UIViewController *vc = [cls performSelector:@selector(controllerWithViewModel:) withObject:viewModel];
                 if (![vc isKindOfClass:UINavigationController.class] &&
                     ![vc isKindOfClass:ADTabBarController.class]) {
                     vc = [[ADNavigationController alloc] initWithRootViewController:vc];
                     [self pushNavigationController:(UINavigationController *)vc];
                 }
                 self.window.rootViewController = vc;
             }
         }
     }];
    
    [[[(NSObject *)self.services
      rac_signalForSelector:@selector(resetRootViewController:)] deliverOnMainThread]
     subscribeNext:^(RACTuple *tuple) {
         @strongify(self)
         UIViewController *vc = tuple.first;
         if (vc) {
             [self.navigationControllers removeAllObjects];
             if (![vc isKindOfClass:UINavigationController.class] &&
                 ![vc isKindOfClass:ADTabBarController.class]) {
                 vc = [[ADNavigationController alloc] initWithRootViewController:vc];
                 [self pushNavigationController:(UINavigationController *)vc];
             }
             self.window.rootViewController = vc;
         }
     }];
}

@end
